home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / Documentation / Development Notes / TroubleShooting / Compile⁄Link Errors next >
Encoding:
Text File  |  1996-09-18  |  9.2 KB  |  221 lines  |  [TEXT/ttxt]

  1. OpenDoc
  2. Development
  3. Framework
  4.                                                                                                                                                                                      
  5. Compile/Link Errors 
  6. ODF Release 2                                                                                                                                                             
  7.  
  8. This document explains some of the compile and link errors you might see due to misuse of Exception and RTTI macros.
  9.  
  10.  
  11. Table of Contents
  12. -----------------
  13. • Misuse of Exception Macros
  14. • Misuse of RTTI Macros
  15.  
  16.  
  17.  
  18. Misuse of Exception Macros
  19.  
  20. Consider the following code:
  21.  
  22. class X
  23. {
  24. public:
  25.     FW_DECLARE_AUTO(X)
  26. public:
  27.     X();
  28.     ~X();
  29. };
  30.  
  31. FW_DEFINE_AUTO(X)
  32.  
  33. X::X()
  34. {
  35.     FW_END_CONSTRUCTOR
  36. }
  37.  
  38. X::~X()
  39. {
  40.     FW_START_DESTRUCTOR
  41. }
  42.  
  43. void foo()
  44. {
  45.     X x1;
  46. }
  47.  
  48. The above code correctly uses the four required macros to make class X be an autodestruct class.  In the examples that follow, we show the compile or link errors that appear if you "forget" or misuse one or more of the macros.  The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
  49.  
  50. 1) You forget to use the FW_DECLARE_AUTO macro.
  51.  
  52. Warning : function has no prototype
  53. Part.cpp line 115   char* FW_PrivGetAutoName(const X*) { return "X"; }  extern FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); extern FW_Pri
  54. Error   : '__dl' is not a struct/union/class member
  55. Part.cpp line 115   r((X*) self); } static void FW_PrivStaticDeleterX(void* p) { X::operator delete(p); } } FW_PrivDestroyProc FW_PrivGetDestroyPr
  56.  
  57. The FW_DECLARE_AUTO declares some functions that are defined by the FW_DEFINE_AUTO macro.   If the FW_DECLARE_AUTO macro is omitted, the compiler will emit errors when the FW_DEFINE_AUTO macro is compiled.
  58.  
  59. 2) You forget to use the FW_DEFINE_AUTO macro.
  60.  
  61. Link Error   : undefined ‘X::operator delete(void*)’ (code)
  62. Referenced from ‘X::~X()’ in Part.cpp
  63. Link Error   : undefined ‘FW_PrivGetDestroyProc(constX*)’ (code)
  64. Referenced from ‘X::~X()’ in Part.cpp
  65. Referenced from ‘X::X()’ in Part.cpp
  66. Link Error   : undefined ‘FW_PrivGetAutoName(constX*)’ (code)
  67. Referenced from ‘X::~X()’ in Part.cpp
  68. Referenced from ‘X::X()’ in Part.cpp
  69.  
  70. This is the reverse of case 1). Here, we assume the FW_DECLARE_AUTO macro is present, but the FW_DEFINE_AUTO macro is missing.  In this case, some functions are declared, but never defined, so the error isn't detected until link time.
  71.  
  72. 3) You forget to use both the FW_DECLARE_AUTO and FW_DEFINE_AUTO macros.
  73.  
  74. Link Error   : undefined ‘FW_PrivGetDestroyProc<1X>(constX*)’ (code)
  75. Referenced from ‘X::~X()’ in Part.cpp
  76. Referenced from ‘X::X()’ in Part.cpp
  77. Link Error   : undefined ‘FW_PrivGetAutoName<1X>(constX*)’ (code)
  78. Referenced from ‘X::~X()’ in Part.cpp
  79. Referenced from ‘X::X()’ in Part.cpp
  80.  
  81. If you forget both the FW_DECLARE_AUTO and the FW_DEFINE_AUTO macros for a class, but then use the FW_END_CONSTRUCTOR and/or FW_START_DESTRUCTOR, you will get link errors like the above.  These errors are not detected until link time because the two functions shown are declared as template functions, but the implementations for the templates are created only through the FW_DEFINE_AUTO macro.
  82.  
  83. 4) You declare the FW_DECLARE_AUTO macro in a private section of your class.
  84.  
  85. This is a more subtle problem.  Suppose you declared your class like this:
  86.  
  87. class X
  88. {
  89.     FW_DECLARE_AUTO(X)
  90. public:
  91.     X();
  92.     ~X();
  93. };
  94.  
  95. Since members of classes are private by default, the member functions defined by the FW_DECLARE_AUTO macro above will be private.  This will result in errors like the following:
  96.  
  97. Error   : illegal access to protected/private member
  98. Part.cpp line 115   r((X*) self); } static void FW_PrivStaticDeleterX(void* p) { X::operator delete(p); } } FW_PrivDestroyProc FW_PrivGetDestroyPr
  99.  
  100. 5) You forget to use FW_NEW when allocating new instances of your class.
  101.  
  102. Suppose that the function foo() above allocated an instance of class X using new, like this:
  103.  
  104. void foo()
  105. {
  106.     X* x1 = new X;
  107. }
  108.  
  109. Dynamically allocated autodestruct classes must be allocated with FW_NEW.  If you forget and use the regular operator new instead, you'll get a compile time error:
  110.  
  111. Error   : illegal access to protected/private member
  112. Part.cpp line 130   X* x2 = new X();
  113.  
  114. This error happens because the FW_DECLARE_AUTO macro declares the standard operator new to be private.
  115.  
  116. 6) You use the FW_NEW macro to create a nonautodestruct object.
  117.  
  118. Once you get in the habit of using FW_NEW, it's easy to make the mistake of using FW_NEW on a nonautodestruct class.  For example, assume class Y is not an autodestruct class, and you write something like this:
  119.  
  120. void foo()
  121. {
  122.     Y* y = FW_NEW(Y, ());
  123. }
  124.  
  125. You should then see a compile error like this:
  126.  
  127. Error   : function call '__nw(unsigned long, FW_CPrivWatcher)' does not match
  128. '__nw(unsigned long)'
  129. '__nw(unsigned long, void *)'
  130. Part.cpp line 135   (Y*) ( new(FW_CPrivWatcher(FW_PrivGetDeleteProc((const Y*)0))) Y(), FW_PrivWatcher_Pop() )
  131.  
  132. This is because FW_NEW uses a overloaded variant of operator new that is only defined by the FW_DECLARE_AUTO macro.
  133.  
  134. 7) You use FW_DEFINE_AUTO twice for the same class.
  135.  
  136. Sometimes it's convient to create a new class by copying code from another class and then renaming.  If you do this by hand and forget to rename the class in the FW_DEFINE_AUTO macro, you'll be invoking the FW_DEFINE_AUTO macro twice for the same class.  This will show up as a compile time error if both instances of the macro are in the same .cpp file, or as a link-time error if they are in separate .cpp files.
  137.  
  138. 8) You use FW_DEFINE_AUTO where FW_DECLARE_AUTO should be used.
  139.  
  140. Suppose you use the FW_DEFINE_AUTO macro in the class declaration by mistake.  This will cause a whole series of errors, beginning with these:
  141.  
  142. Error   : illegal struct/union/enum/class definition
  143. Part.cpp line 113   char* FW_PrivGetAutoName(const X*) { return "X"; }  extern FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); extern FW_Priv
  144. Error   : declaration syntax error
  145. Part.cpp line 114   public:
  146. Error   : declaration syntax error
  147. Part.cpp line 115   X();
  148. Error   : declaration syntax error
  149. Part.cpp line 116   ~X();
  150. Error   : declaration syntax error
  151. Part.cpp line 117   };
  152.  
  153. 9) You use FW_DECLARE_AUTO where FW_DEFINE_AUTO should be used.
  154.  
  155. Suppose you use the FW_DECLARE_AUTO macro in the .cpp file by mistake.  This will cause at least one compile-time error:
  156.  
  157. Error   : declaration syntax error
  158. Part.cpp line 119   friend char* FW_PrivGetAutoName(const X*); friend FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); friend FW_PrivDeletePro
  159.  
  160.  
  161.  
  162. Misuse of RTTI Macros
  163.  
  164. Consider the following code:
  165.  
  166. class A
  167. {
  168. public:
  169.     FW_DECLARE_CLASS
  170. public:
  171.     A() {}
  172.     virtual ~A() {}
  173. };
  174.  
  175. class B : public A
  176. {
  177. public:
  178.     FW_DECLARE_CLASS
  179. public:
  180.     B() {}
  181.     virtual ~B() {}
  182. };
  183.  
  184. FW_DEFINE_CLASS_M0(A)
  185. FW_DEFINE_CLASS_M1(B, A)
  186.  
  187. void foo()
  188. {
  189.     A* a = new B();
  190.     B* b = FW_DYNAMIC_CAST(B, a);
  191. }
  192.  
  193. The above code correctly uses the FW_DECLARE_CLASS and FW_DEFINE_CLASS_Mn macros required to make classes have runtime type identification.  In the examples that follow, we show the compile or link errors that appear if you forget or misuse one or more of the macros.  The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
  194.  
  195. 1) You forget to use the FW_DECLARE_CLASS macro.
  196.  
  197. Suppose you left out the FW_DECLARE_CLASS macro for class A. You'd then get these compile-time errors:
  198.  
  199. Error   : 'gAncestors' is not a struct/union/class member
  200. Part.cpp line 124   const FW_SClassInfoPtr A::gAncestors[] = { 0 }; const size_t A::gAncestorOffsets[] = { 0 }; FW_SClassInfo A::gClassInfo = 
  201. Error   : 'gClassInfo' is not a struct/union/class member
  202. Part.cpp line 125   const FW_SClassInfoPtr B::gAncestors[] = { (&A::gClassInfo), 0 }; const size_t B::gAncestorOffsets[] = { (((char*)((A*)((
  203. Error   : 'PrivVirtualGetClassInfo' is not a struct/union/class member
  204. Part.cpp line 1   
  205.  
  206. The FW_DECLARE_CLASS macro declares some static data members and a virtual function.  If you forget the FW_DECLARE_CLASS macro but use the FW_DEFINE_CLASS_Mn macro, the compiler emit errors for the references to undeclared data and functions.
  207.  
  208. 2) You forget to use the FW_DEFINE_CLASS_Mn macro.
  209.  
  210. Suppose you left out the FW_DEFINE_CLASS_M0 macro for class A. You'd then get the following link-time errors:
  211.  
  212. Link Error   : undefined ‘A::gClassInfo’ (data)
  213. Referenced from ‘FW_PrivStaticGetClassInfo<1A>(A*)’ in Part.cpp
  214. Referenced from ‘B::gAncestors’ in Part.cpp
  215. Link Error   : missing vtable ‘A::__vt’
  216. Check that all virtual functions and static members are defined
  217.  
  218. In this case, the members are declared but never defined (implemented), so the error doesn't show up until link time.  Note in particular the last link error. Many C++ compilers generate the vtable for a class in the translation unit that implements the first virtual function declared for the class. Since by convention, we normally place the FW_DECLARE_CLASS macro at the top of the class declaration, the virtual function declared by the FW_DECLARE_CLASS macro is the first virtual function.  Since it isn't implemented, the compiler doesn't generate the vtable; hence the error "missing vtable ‘A::__vt’".
  219.  
  220. © 1993 - 1996 Apple Computer, Inc. All rights reserved.
  221. Apple, the Apple Logo, Macintosh, and OpenDoc are trademarks of Apple Computer, Inc., registered in the United States and other countries.